<?php

namespace fwkit\Http;

use Swoole\Coroutine;
use Swoole\Coroutine\Http\Client as SwooleClient;

class CoClient extends Client
{
    protected $files = [];

    public function setReferer(string $referer)
    {
        $this->headers['Referer'] = $referer;
        return $this;
    }

    public function withFile(string $fieldName, string $path, ?string $mimeType = null, ?string $fileName = null)
    {
        $this->isMultipart = true;
        $this->files[] = [$fieldName, $path, $mimeType, $fileName];
        return $this;
    }

    public function send(?string $saveTo = null)
    {
        $this->executed = true;
        $method = $this->method;
        $body = $this->body;
        $timeout = $this->timeout;
        $headers = $this->headers;
        $urlData = parse_url($this->url);

        // if (is_array($body) && !$this->isMultipart) {
        //     $headers['Content-Type'] = 'application/x-www-form-urlencoded';
        //     $body = http_build_query($body);
        // }

        $host = $urlData['host'];
        $ssl = isset($urlData['scheme']) ? $urlData['scheme'] == 'https' : false;
        $port = isset($urlData['port']) ? intval($urlData['port']) : ($ssl ? 443 : 80);
        $client = new SwooleClient($host, $port, $ssl);
        $setting = ['timeout' => $timeout, 'keep_alive' => false];
        if ($this->sslCert && $this->sslKey) {
            $setting['ssl_cert_file'] = $this->sslCert;
            $setting['ssl_key_file'] = $this->sslKey;
        }
        $client->set($setting);
        $client->setHeaders($headers);

        $path = empty($urlData['path']) ? '/' : $urlData['path'];
        $query = empty($urlData['query']) ? '' : $urlData['query'];
        if ($this->query) {
            $q = is_array($this->query) ? http_build_query($this->query) : strval($this->query);
            $query .= ($query ? '&' : '') . $q;
        }

        if ($query) {
            $path = $path . '?' . $query;
        }

        if ($method === 'POST') {
            if ($this->files) {
                foreach ($this->files as [$fieldName, $path, $mimeType, $fileName]) {
                    $client->addFile($path, $fieldName, $fileName, $mimeType);
                }
            }

            $client->post($path, $body);
        } else {
            $client->get($path);
        }

        $this->executed = true;
        $data = $client->body;

        if ($saveTo === null) {
            if ($client->errCode) {
                throw new \Exception(socket_strerror($client->errCode), $client->errCode);
            } else {
                $this->response = ['responseText' => $data] + $client->headers;
                $this->responseHeaders = $client->headers;
                $this->responseText = $data;
            }
        } else {
            $fh = fopen($saveTo, 'w');
            Coroutine::fwrite($fh, $data);
            fclose($fh);
        }

        $client->close();
        return $this;
    }
}
